package com.moli.iov.his.remote.impl;

import com.moli.iov.common.hbase.service.IHbaseService;
import com.moli.iov.his.dto.VehicleTrajectoryReqDTO;
import com.moli.iov.his.dto.VehicleTrajectoryResDTO;
import com.moli.iov.his.remote.VehicleTrajectoryService;
import com.moli.iov.his.util.AdapterUtil;
import com.moli.iov.protocol.codec.DataDecoder;
import com.moli.iov.protocol.model.realtime.RealTimeInfoReq;
import com.moli.iov.protocol.model.realtime.VehicleAllReq;
import com.moli.iov.protocol.model.realtime.VehicleGpsReq;
import com.moli.iov.rest.RestResponse;
import com.moli.iov.util.DateUtil;
import com.moli.iov.vehicle.service.IVehicleBaseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * @ClassName VehicleTrajectoryServiceImpl
 * @Description TODO
 * @Author 李伟松
 * @CreateDate 2019-09-09 下午 4:06
 * @UpdateDate 2019-09-09 下午 4:06
 * @Version 1.0
 */
@Service
@Slf4j
public class VehicleTrajectoryServiceImpl implements VehicleTrajectoryService {

    @Resource
    IVehicleBaseService vehicleBaseService;

    @Resource
    IHbaseService hbaseService;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    private static final String TABLE_NAME = "moli:org_iov_realtime";

    @Override
    public List<VehicleTrajectoryResDTO> listVehicleTrajectory(VehicleTrajectoryReqDTO dto) {
        //参数是否合法-基本判断
        Boolean pass = checkListVehicleTrajectory(dto);
        if (!pass) {
            return null;
        }
        //参数是否合法-数据判断
        String vin = getVinByNumType(dto);
        if (StringUtils.isEmpty(vin)) {
            return null;
        }

        long startTime = System.currentTimeMillis();
        //查询轨迹
        List<VehicleTrajectoryResDTO> list = listTrajectoryByAsync(dto.getStartTime(), dto.getEndTime(), vin);
        long endTime = System.currentTimeMillis();
        log.info("总时长:{}",(endTime-startTime));
        return list;
    }


//    static long DAY_TIME = 86400000*3L;
    static long DAY_TIME = 86400000;

    //将时间按天分割成多段
    private static List<Date[]> getTimeList(Date startDate, Date endDate){
        long startTime = startDate.getTime();
        long endTime = endDate.getTime();

        List<Date[]> timeList = new ArrayList<>();
        int count = 1;
        while (endTime - (DAY_TIME * count) > startTime) {
            Date[] l = {new Date(endTime - DAY_TIME * count), new Date(endTime - (DAY_TIME * (count - 1)))};
            timeList.add(l);
            count++;
        }
        Date[] end = {new Date(startTime), new Date(endTime - (DAY_TIME * (count - 1)))};
        timeList.add(end);
        return timeList;
    }

    public List<VehicleTrajectoryResDTO> listTrajectoryByAsync(Date startDate, Date endDate, String vin) {

        List<Date[]> timeList = getTimeList(startDate,endDate);
        CountDownLatch countDownLatch = new CountDownLatch(timeList.size());
        List<VehicleTrajectoryResDTO> vector = new Vector();
        for(int i = 0 ; i < timeList.size(); i ++){
            int finalIndex = i;
            taskExecutor.execute(()->{
                Date start = timeList.get(finalIndex)[0];
                Date end = timeList.get(finalIndex)[1];
                List<VehicleTrajectoryResDTO> tmpList =  listTrajectory( start,  end,  vin);
                vector.addAll(tmpList);
                countDownLatch.countDown();
            });
        }
        try {
            countDownLatch.await();
            List<VehicleTrajectoryResDTO> list = new ArrayList<>(vector);


            return list;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("同步全部车辆数据 完成 ");
        return null;
    }


    public List<VehicleTrajectoryResDTO> listTrajectory(Date startDate, Date endDate, String vin) {

        List<VehicleTrajectoryResDTO> list = new ArrayList<>();

        String startRow = getRowKey(vin, endDate);
        String endRow = getRowKey(vin, startDate);
        try {
            long startTime22 = System.currentTimeMillis();
            //查询hbase获取byte[] 集合
            List<byte[]> realtimeList = hbaseService.getDataResult(startRow, endRow, TABLE_NAME);
            long endTime22 = System.currentTimeMillis();
            log.info("查询hbase时长:{}",(endTime22-startTime22));

            //获取上一次的报文
            RealTimeInfoReq previous = null;
            long startTime = System.currentTimeMillis();

            for (int i = realtimeList.size()-1; i >-1; i--) {

                //解析当前报文
                RealTimeInfoReq req = new RealTimeInfoReq();
                DataDecoder<RealTimeInfoReq> decoder = new DataDecoder<>();
                decoder.decode(req, realtimeList.get(i));

                //报文合法验证
                if (req == null
                        || req.getVehicleAllReq()==null
                        || req.getVehicleGpsReq() == null
                        || req.getVehicleGpsReq().getLongitude() < 73
                        || req.getVehicleGpsReq().getLongitude() > 135
                        ) {
                    continue;
                }




                //如果上一次报文为null则赋值
                if (previous == null) {
                    previous = req;
                    VehicleTrajectoryResDTO res = AdapterUtil.adapterTrajectory(req);
                    if (res != null) {
                        list.add(res);
                    }
                    continue;
                }


                VehicleAllReq vehicleAll = req.getVehicleAllReq();
                VehicleGpsReq gps = req.getVehicleGpsReq();
                VehicleAllReq previousVehicleAll = previous.getVehicleAllReq();
                VehicleGpsReq previousGps = previous.getVehicleGpsReq();

                //判断车辆是否移动
                if (vehicleAll.getOdometer() == previousVehicleAll.getOdometer()
                        || (gps.getLongitude() == previousGps.getLongitude() && gps.getLatitude() == previousGps.getLatitude())
                        ) {
                    continue;
                } else {
                    //车辆移动，添加到集合中，并对上一次报文进行覆盖
                    VehicleTrajectoryResDTO res = AdapterUtil.adapterTrajectory(req);
                    if (res != null) {
                        previous = req;
                        list.add(res);
                    }
                }
            }

            long endTime = System.currentTimeMillis();
            log.info("反序列化执行时长:{}", (endTime - startTime));
            return list;

        } catch (Exception e) {
            log.info("查询hbase出错，{}", e);

        }
        return null;
    }

    public static void main(String[] args) {
        System.out.println(getRowKey("LNBSCB3F4JW176319",new Date(1555775999000L)));
        System.out.println(getRowKey("LNBSCB3F4JW176319",new Date(1556639999000L)));
    }

    private static String getRowKey(String vin, Date date) {
        return vin + "_" + (Long.MAX_VALUE - date.getTime());
    }

    //根据入参类型获取车架号
    private String getVinByNumType(VehicleTrajectoryReqDTO dto) {
        String vin = null;
        if ("1".equals(dto.getNumType())) {  //1:代表车牌号
            try {
                //根据车牌号查询vin
                RestResponse<String> numResult = vehicleBaseService.queryVinByLicense(dto.getNum());
                vin = numResult.getData();
            } catch (Exception e) {
                log.error("[getVinByType][{}]", e.getMessage());
                return null;
            }
        } else {
            //2:代表车辆vin号码
            vin = dto.getNum();
        }
        return vin;
    }

    //轨迹回放入参基础校验
    Boolean checkListVehicleTrajectory(VehicleTrajectoryReqDTO dto) {
        if (dto == null
                || dto.getEndTime() == null
                || dto.getStartTime() == null
                || StringUtils.isEmpty(dto.getNumType())
                || StringUtils.isEmpty(dto.getNum())) {
            return false;
        }
        return true;
    }

//        HistoryRemoteService historyRemoteService =SpringContextUtils.getBean("historyRemoteService");
//        VehicleTrajectoryReqDTO dto = new VehicleTrajectoryReqDTO();
//        dto.setNumType("2");
//        dto.setNum("LNBSCB3F0JW176270");
//        dto.setStartTime(new Date(1564637011000L));
//        dto.setEndTime(new Date(1565069011000L));
//        for (int i = 0; i < 10; i++) {
//            RestResponse<List<VehicleTrajectoryResDTO>> res = historyRemoteService.listVehicleTrajectory(dto);
//            if(res!=null && res.getData()!=null){
//                System.out.println(res.getData().size());
//            }
//        }
}
